package tt.dz.biz.service.rpc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.math.BigDecimal;
import javax.annotation.Resource;
import org.apache.avro.Protocol;
import org.apache.avro.Protocol.Message;
import org.apache.avro.generic.GenericRecord;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import tt.dz.biz.dao.financial.MerchantDAO;
import tt.dz.biz.dao.order.OrderServiceDAOImpl;
import tt.dz.biz.dao.trade.TradeDAOImpl;
import tt.dz.biz.dao.user.OnlineAccountDAO;
import tt.dz.biz.service.card.CardTypeServiceImpl;
import tt.dz.biz.service.common.CommonService;
import tt.dz.common.BigDecimalUtil;
import tt.dz.common.BusinessException;
import tt.dz.common.DZStringUtil;
import tt.dz.common.DateUtil;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.CardType;
import tt.dz.common.DzConstants.PayType;
import tt.dz.common.DzConstants.accountingState;
import tt.dz.common.DzConstants.payState;
import tt.dz.common.DzConstants.userType;
import tt.dz.common.DzErrorCode;
import tt.dz.common.DzErrorCode.CardErrorCode;
import tt.dz.common.DzErrorCode.CommonErrorCode;
import tt.dz.common.DzErrorCode.ExceptionErrorCode;
import tt.dz.common.DzErrorCode.MerchErrorCode;
import tt.dz.common.DzErrorCode.TranErrorCode;
import tt.dz.common.LogUtil;
import tt.dz.vo.MerchantVO;
import tt.dz.vo.OnlineAccountVO;
import tt.dz.vo.OrderServiceVO;
import tt.dz.vo.TranInfoVO;

@Service("rpcOnlineCardService")
public class RPCOnlineCardService
  implements RPCBaseService
{
  @Resource(name="onlineAccountDAO")
  OnlineAccountDAO onlineAccountDAO;
  @Resource(name="orderServiceDAO")
  private OrderServiceDAOImpl orderService;
  @Resource(name="commonService")
  private CommonService commonService;
  @Resource(name="cardTypeServiceImpl")
  private CardTypeServiceImpl cardTypeServiceImpl;
  @Resource(name="tradeDAO")
  private TradeDAOImpl tradeDAO;
  @Resource(name="merchantDAO")
  private MerchantDAO merchantDAO;
  @Value("${recharge.service.no}")
  private String rechargeServiceNo;
  
  public Object execute(Protocol.Message message, Object request, Protocol protocol)
    throws Exception
  {
    Object req = ((GenericRecord)request).get("req");
    JSONObject reqObj = JSON.parseObject(req.toString());
    String cardNo = reqObj.getString("cardNo");
    if (StringUtils.isBlank(cardNo)) {
      throw new BusinessException(DzErrorCode.CommonErrorCode.PARAM_REQUIRED.value(), 
        DzErrorCode.CommonErrorCode.PARAM_REQUIRED.getDesc(), 
        DzErrorCode.CommonErrorCode.PARAM_REQUIRED.getDesc());
    }
    String cardType = this.cardTypeServiceImpl.getCardType(cardNo);
    if (!DzConstants.CardType.ONLINE_CARD.value().equals(cardType)) {
      throw new BusinessException(DzErrorCode.CardErrorCode.CARD_TYPE_ERROR.value(), 
        DzErrorCode.CardErrorCode.CARD_TYPE_ERROR.getDesc(), 
        DzErrorCode.CardErrorCode.CARD_TYPE_ERROR.getDesc());
    }
    String methodName = message.getName();
    if ("rechargeOnlineAccount".equals(methodName)) {
      return recharge(request, cardType);
    }
    if ("queryOnlineAccountBal".equals(methodName)) {
      return queryOnlineAccountBal(request);
    }
    if ("deductOnlineAccountBal".equals(methodName)) {
      return deductOnlineAccountBal(request);
    }
    return "";
  }
  
  private Object recharge(Object request, String cardType)
    throws Exception
  {
    JSONObject resultJson = new JSONObject();
    try
    {
      Object req = ((GenericRecord)request).get("req");
      String tradeReq = req.toString();
      TranInfoVO tranInfoVO = (TranInfoVO)JSONObject.parseObject(tradeReq, TranInfoVO.class);
      tranInfoVO.setCardType(cardType);
      tranInfoVO.setServiceNo(this.rechargeServiceNo);
      if ((tranInfoVO.getServiceNo() == null) || (tranInfoVO.getPaymentAmount() == null) || 
        (tranInfoVO.getPayTypeCode() == null) || (tranInfoVO.getPayStateCode() == null) || 
        (tranInfoVO.getCardNo() == null) || (StringUtils.isBlank(tranInfoVO.getAppId())))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.getDesc());
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.value());
        return resultJson.toJSONString();
      }
      if ((DzConstants.PayType.THIRD_REALTIME_PAY.value().equals(tranInfoVO.getPayTypeCode())) && 
        (StringUtils.isBlank(tranInfoVO.getChannelCode())))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.value());
        resultJson.put("errorMsg", "第三方实时支付时，支付渠道不能为空。");
        return resultJson.toJSONString();
      }
      if (!DzConstants.payState.PAY_SUCCESS.value().equals(tranInfoVO.getPayStateCode()))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.TranErrorCode.PAY_STATE_ERROR.getDesc());
        resultJson.put("errorCode", DzErrorCode.TranErrorCode.PAY_STATE_ERROR.value());
        return resultJson.toJSONString();
      }
      OrderServiceVO serviceVO = this.orderService.queryServiceByCode(tranInfoVO.getServiceNo());
      if (serviceVO == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", 
          DzErrorCode.TranErrorCode.SERVICE_NOT_FOUND.getDesc() + ",服务编码为：" + tranInfoVO.getServiceNo());
        resultJson.put("errorCode", DzErrorCode.TranErrorCode.SERVICE_NOT_FOUND.value());
        return resultJson.toJSONString();
      }
      if (tranInfoVO.getAppId().length() > 3)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.CommonErrorCode.PARAM_TOO_LARGE.getDesc() + ",appId只能3位。");
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.PARAM_TOO_LARGE.value());
        return resultJson.toJSONString();
      }
      if (StringUtils.isBlank(tranInfoVO.getReceiver()))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.MerchErrorCode.MERCHANT_IS_REQUIRED.getDesc());
        resultJson.put("errorCode", DzErrorCode.MerchErrorCode.MERCHANT_IS_REQUIRED.value());
        return resultJson.toJSONString();
      }
      OnlineAccountVO onlineVO = this.onlineAccountDAO.queryOnlineCardByNo(tranInfoVO.getCardNo());
      if (onlineVO == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CardErrorCode.NOT_FOUND.value());
        resultJson.put("errorMsg", DzErrorCode.CardErrorCode.NOT_FOUND.getDesc());
        return resultJson.toJSONString();
      }
      MerchantVO mv = this.merchantDAO.queryMerchantByCode(tranInfoVO.getReceiver());
      if (mv == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.MerchErrorCode.NOT_FOUND.getDesc());
        resultJson.put("errorCode", DzErrorCode.MerchErrorCode.NOT_FOUND.value());
        return resultJson.toJSONString();
      }
      tranInfoVO.setAccountState(DzConstants.accountingState.WAIT_FOR_ACCOUNTING.value());
      tranInfoVO.setPlatTime(DateUtil.getDBCurrentTime());
      tranInfoVO.setAccountingDate(this.commonService.getAccountingDate());
      tranInfoVO.setOriginalPayer(tranInfoVO.getCardNo());
      tranInfoVO.setOriginalPayerType(DzConstants.userType.PERSONAL_CUSTOMER.value());
      tranInfoVO.setPayer(onlineVO.getUserId());
      tranInfoVO.setPayerType(DzConstants.userType.PERSONAL_CUSTOMER.value());
      tranInfoVO.setReceiverType(DzConstants.userType.MERCHANT_CUSTOMER.value());
      tranInfoVO.setReceiverName(mv.getShortName());
      String currentDate = DateUtil.getDateFormatter();
      String seqNo = DZStringUtil.getFixedLengthString(8, 
        String.valueOf(this.tradeDAO.querySequence("seq_trade_no")));
      String tradNo = String.valueOf(DzConstants.userType.OFFLINE_CUSTOMER.value()) + tranInfoVO.getAppId() + 
        currentDate + seqNo;
      
      tranInfoVO.setTradeNo(tradNo);
      int n = this.tradeDAO.insertTranInfo(tranInfoVO);
      if (n == 0) {
        throw new BusinessException(DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.value(), 
          DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.getDesc(), 
          DzErrorCode.TranErrorCode.SAVE_TRAN_INFO_FAIL.getDesc());
      }
      OnlineAccountVO onlineAccount = new OnlineAccountVO();
      onlineAccount.setCardNo(tranInfoVO.getCardNo());
      onlineAccount.setAcctBal(tranInfoVO.getPaymentAmount());
      onlineAccount.setLastDate(DateUtil.getDBCurrentTime());
      if (!this.onlineAccountDAO.updateOnlineAccountBal(onlineAccount)) {
        throw new BusinessException(DzErrorCode.ExceptionErrorCode.COMMON_EXCEPTION.value(), 
          DzErrorCode.ExceptionErrorCode.COMMON_EXCEPTION.getDesc(), 
          DzErrorCode.ExceptionErrorCode.COMMON_EXCEPTION.getDesc());
      }
      OnlineAccountVO rsVO = this.onlineAccountDAO.queryOnlineCardByNo(tranInfoVO.getCardNo());
      if (onlineVO.getAcctBal() == null) {
        resultJson.put("acctBal", "0");
      } else {
        resultJson.put("acctBal", rsVO.getAcctBal());
      }
      resultJson.put("isSuccess", Integer.valueOf(1));
      return resultJson.toJSONString();
    }
    catch (Exception e)
    {
      LogUtil.error("离线卡充值异常，参数为：" + request.toString());
      throw e;
    }
  }
  
  public Object queryOnlineAccountBal(Object request)
    throws Exception
  {
    JSONObject resultJson = new JSONObject();
    try
    {
      Object req = ((GenericRecord)request).get("req");
      JSONObject reqObj = JSON.parseObject(req.toString());
      String cardNo = reqObj.getString("cardNo");
      if (StringUtils.isBlank(cardNo))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.getDesc());
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.value());
        return resultJson.toJSONString();
      }
      OnlineAccountVO onlineVO = this.onlineAccountDAO.queryOnlineCardByNo(cardNo);
      if (onlineVO == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CardErrorCode.NOT_FOUND.value());
        resultJson.put("errorMsg", DzErrorCode.CardErrorCode.NOT_FOUND.getDesc());
        return resultJson.toJSONString();
      }
      resultJson.put("isSuccess", Integer.valueOf(1));
      if (onlineVO.getAcctBal() == null) {
        resultJson.put("acctBal", "0");
      } else {
        resultJson.put("acctBal", onlineVO.getAcctBal());
      }
      return resultJson.toJSONString();
    }
    catch (Exception e)
    {
      LogUtil.error("线上卡查询余额异常，参数为：" + request.toString());
      throw e;
    }
  }
  
  private Object deductOnlineAccountBal(Object request)
    throws Exception
  {
    JSONObject resultJson = new JSONObject();
    try
    {
      Object req = ((GenericRecord)request).get("req");
      JSONObject reqObj = JSON.parseObject(req.toString());
      String cardNo = reqObj.getString("cardNo");
      String paymentAmount = reqObj.getString("paymentAmount");
      if ((StringUtils.isBlank(cardNo)) || (StringUtils.isBlank(paymentAmount)))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.getDesc());
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.PARAM_REQUIRED.value());
        return resultJson.toJSONString();
      }
      if (new BigDecimal(paymentAmount).compareTo(new BigDecimal("0")) == -1)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorMsg", "paymentAmount" + DzErrorCode.CommonErrorCode.CAN_NOT_MINUS.getDesc());
        resultJson.put("errorCode", DzErrorCode.CommonErrorCode.CAN_NOT_MINUS.value());
        return resultJson.toJSONString();
      }
      OnlineAccountVO rsOnlineVO = this.onlineAccountDAO.queryOnlineCardByNo(cardNo);
      if (rsOnlineVO == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CardErrorCode.NOT_FOUND.value());
        resultJson.put("errorMsg", DzErrorCode.CardErrorCode.NOT_FOUND.getDesc());
        return resultJson.toJSONString();
      }
      if (rsOnlineVO.getAcctBal().compareTo(new BigDecimal(paymentAmount)) == -1)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CardErrorCode.BALANCE_NOT_ENOUGH.value());
        resultJson.put("errorMsg", DzErrorCode.CardErrorCode.BALANCE_NOT_ENOUGH.getDesc());
        return resultJson.toJSONString();
      }
      OnlineAccountVO onlineVO = new OnlineAccountVO();
      onlineVO.setCardNo(cardNo);
      onlineVO.setAcctBal(BigDecimalUtil.sub(new BigDecimal("0"), new BigDecimal(paymentAmount)));
      onlineVO.setLastDate(DateUtil.getDBCurrentTime());
      if (!this.onlineAccountDAO.updateOnlineAccountBal(onlineVO))
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.ExceptionErrorCode.COMMON_EXCEPTION.value());
        resultJson.put("errorMsg", DzErrorCode.ExceptionErrorCode.COMMON_EXCEPTION.getDesc());
        return resultJson.toJSONString();
      }
      rsOnlineVO = this.onlineAccountDAO.queryOnlineCardByNo(cardNo);
      if (rsOnlineVO == null)
      {
        resultJson.put("isSuccess", Integer.valueOf(0));
        resultJson.put("errorCode", DzErrorCode.CardErrorCode.NOT_FOUND.value());
        resultJson.put("errorMsg", DzErrorCode.CardErrorCode.NOT_FOUND.getDesc());
        return resultJson.toJSONString();
      }
      if (rsOnlineVO.getAcctBal() == null) {
        resultJson.put("acctBal", "0");
      } else {
        resultJson.put("acctBal", rsOnlineVO.getAcctBal());
      }
      resultJson.put("isSuccess", Integer.valueOf(1));
      return resultJson.toJSONString();
    }
    catch (Exception e)
    {
      LogUtil.error("线上卡扣款异常，参数为：" + request.toString());
      throw e;
    }
  }
}
